#ifndef __FG__PLATFORM__H__
#define __FG__PLATFORM__H__
#define FG_PLATFORM_WIN 1
#define FG_PLATFORM_LINUX 2
#define FG_PLATFORM_APPLE 3
#define FG_PLATFORM_SYMBIAN 4
#define FG_PLATFORM_APPLE_IOS 5
#define FG_PLATFORM_ANDROID 6
#define FG_PLATFORM_TEGRA2 7
#define FG_PLATFORM_NACL 8

//#define FG_ENABLE_SSL 1
#if FG_ENABLE_SSL
#define EVENT__HAVE_OPENSSL
#endif

#define FG_ARCHITECTURE_32 1
#define FG_ARCHITECTURE_64 2

/* See if we can use __forceinline or if we need to use __inline instead */
#if FG_COMPILER == FG_COMPILER_MSVC
#   if FG_COMP_VER >= 1200
#       define FORCEINLINE __forceinline
#   endif
#elif defined(__MINGW32__)
#   if !defined(FORCEINLINE)
#       define FORCEINLINE __inline
#   endif
#else
#   define FORCEINLINE __inline
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Find the arch type */
#if defined(__x86_64__) || defined(_M_X64) || defined(__powerpc64__) || defined(__alpha__) || defined(__ia64__) || defined(__s390__) || defined(__s390x__)
#   define FG_ARCH_TYPE FG_ARCHITECTURE_64
#else
#   define FG_ARCH_TYPE FG_ARCHITECTURE_32
#endif

/* Finds the current platform */
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if defined( __WIN32__ ) || defined( _WIN32 ) || defined(_WINDOWS) || defined(WIN) || defined(_WIN64) || defined( __WIN64__ )
#   define FG_PLATFORM FG_PLATFORM_WIN
//////////////////////////////////////////////////////////////////////////
#elif defined( __APPLE_CC__) || defined(__APPLE__) || defined(__OSX__)
// Device                                                     Simulator
// Both requiring OS version 4.0 or greater
#   if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 40000 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
#       define FG_PLATFORM FG_PLATFORM_APPLE_IOS
#   else
#       define FG_PLATFORM FG_PLATFORM_APPLE
#   endif
//////////////////////////////////////////////////////////////////////////
#elif defined(linux) && defined(__arm__)
// TODO: This is NOT the correct way to detect the Tegra 2 platform but it works for now.
// It doesn't appear that GCC defines any platform specific macros.
#   define FG_PLATFORM FG_PLATFORM_TEGRA2
#elif defined(__ANDROID__)
#   define FG_PLATFORM FG_PLATFORM_ANDROID
//////////////////////////////////////////////////////////////////////////
#elif defined( __native_client__ )
#   define FG_PLATFORM FG_PLATFORM_NACL
#   ifndef FG_STATIC_LIB
#       error FG must be built as static for NaCl (FG_STATIC=true in cmake)
#   endif
#   ifdef FG_BUILD_RENDERSYSTDDNF_D3D9
#       error d3d9 is nor supported on NaCl (OFG_BUILD_RENDERSYSTDDNF_D3D9 false in cmake)
#   endif
#   ifdef FG_BUILD_RENDERSYSTDDNF_GL
#       error gl is nor supported on NaCl (OFG_BUILD_RENDERSYSTDDNF_GL=false in cmake)
#   endif
#   ifndef FG_BUILD_RENDERSYSTDDNF_GLES2
#       error GLES2 render system is needed for NaCl (OFG_BUILD_RENDERSYSTDDNF_GLES2=false in cmake)
#   endif
#else
#   define FG_PLATFORM FG_PLATFORM_LINUX
#endif

//----------------------------------------------------------------------------
// Linux/Apple/iOs/Android/Symbian/Tegra2/NaCl Settings
#if FG_PLATFORM == FG_PLATFORM_LINUX || FG_PLATFORM == FG_PLATFORM_APPLE || FG_PLATFORM == FG_PLATFORM_APPLE_IOS || FG_PLATFORM == FG_PLATFORM_ANDROID || FG_PLATFORM == FG_PLATFORM_TEGRA2 || FG_PLATFORM == FG_PLATFORM_NACL

//#include <syswait.h>

// Enable GCC symbol visibility
#   if defined( FG_GCC_VISIBILITY )
#       define _FGExport  __attribute__ ((visibility("default")))
#       define _FGPrivate __attribute__ ((visibility("hidden")))
#   else
#       define _FGExport
#       define _FGPrivate
#   endif

// A quick define to overcome different names for the same function
#   define stricmp strcasecmp

// Unlike the Win32 compilers, Linux compilers seem to use DEBUG for when
// specifying a debug build.
// (??? this is wrong, on Linux debug builds aren't marked in any way unless
// you mark it yourself any way you like it -- zap ???)
//#   if defined(_DEBUG) || defined(DEBUG)
//#       define FG_DEBUG_MODE 1
//#   endif

// Always enable unicode support for the moment
// Perhaps disable in old versions of gcc if necessary
#define FG_UNICODE_SUPPORT 1
#define MAX_PATH 255

#define FG_EXPORT extern "C" __attribute ((visibility("default")))

#endif

//#define FG_LIBEVENT_SRC		

#include <stdint.h>
#include <chrono>
#include <functional>
#include <assert.h>
#include <string>
#include <map>
#include <iostream>
#include <vector>
#include <list>
#include <memory>

#include <string>
#include <algorithm>
#include <cmath>
#include <time.h>
#include <sstream>
#include <stdio.h>
#include <Depends/common/lexical_cast.hpp>

#if FG_PLATFORM == FG_PLATFORM_WIN
#include <crtdbg.h>
#define FGASSERT(exp_, msg_, file_, func_)  \
    std::string strInfo("Message:");        \
    strInfo += msg_ + std::string(" don't exist or some warning") + std::string("\n\nFile:") + std::string(file_) + std::string("\n Function:") + func_; \
    MessageBoxA(0, strInfo.c_str(), ("Error_"#exp_), MB_RETRYCANCEL | MB_ICONERROR); \
    assert(0);
#else
#define FGASSERT(exp_, msg_, file_, func_)
#endif

#ifndef _MSC_VER
#include <sys/time.h>
#include <unistd.h>
#define EPOCHFILETIME 11644473600000000ULL
#else
#include <WinSock2.h>
#include <windows.h>
#include <time.h>
#include <process.h>
#define EPOCHFILETIME 11644473600000000Ui64
#endif

#define ELPP_DISABLE_DEFAULT_CRASH_HANDLING

#if FG_PLATFORM == FG_PLATFORM_WIN
#define FGSPRINTF sprintf_s
#define FGSTRICMP _stricmp
#define FGSLEEP(s) Sleep((DWORD)s) //millisecond
#define FGGetPID() lexical_cast<std::string>(getpid())
#else
#define FGSPRINTF snprintf
#define FGSTRICMP strcasecmp
#define FGSLEEP(s) usleep(s*1000) //millisecond
#define FGGetPID() lexical_cast<std::string>(getpid())
#endif

namespace FragrantGrass
{
	// Integer formats of fixed bit width
	typedef uint32_t UINT32;
	typedef uint16_t UINT16;
	typedef uint8_t UINT8;
	typedef int32_t INT32;
	typedef int16_t INT16;
	typedef int8_t INT8;
	typedef uint64_t UINT64;
	typedef int64_t INT64;
	typedef int64_t SOCK;
}

#define FG_SHARE_PTR std::shared_ptr
#define FG_NEW new

#define GET_CLASS_NAME(className) (#className)

#if FG_PLATFORM == FG_PLATFORM_WIN
#define FG_STRICMP _stricmp
#else
#define FG_STRICMP strcasecmp
#endif

namespace FragrantGrass
{
	template<typename DTYPE>
	bool StrTo(const std::string& strValue, DTYPE& nValue)
	{
		try
		{
			nValue = lexical_cast<DTYPE>(strValue);
			return true;
		}
		catch (...)
		{
			return false;
		}

		return false;
	}

	inline int64_t GetTimeMSEx()
	{
		return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
	}

	//millisecond
	inline int64_t GetTimeMS()
	{
		return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
	}

	//second
	inline int64_t GetTimeS()
	{
		return GetTimeMS() / 1000;
	}
}
#endif//__FG__PLATFORM__H__